﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MotionCS.Helper;
using MotionCS.Enumerate;

namespace MotionCS.Path
{
    public class Position
    {
        /// <summary>
        /// x轴位置
        /// </summary>
        public float x { get; set; }
        /// <summary>
        /// Y轴位置
        /// </summary>
        public float y { get; set; }
        /// <summary>
        /// 坐标位置
        /// </summary>
        /// <param name="xc"></param>
        /// <param name="yc"></param>
        public Position(float xc, float yc)
        {
            x = xc;
            y = yc;
        }
    }

    public class MapPoint
    {
        /// <summary>
        /// 行数
        /// </summary>
        public Int32 Row;
        /// <summary>
        /// 列数
        /// </summary>
        public Int32 Column;
        /// <summary>
        /// 点拍
        /// </summary>
        public List<Position> Positions = new List<Position>();
    }

    public class MapFlying
    {
        /// <summary>
        /// 行数
        /// </summary>
        public Int32 Row;
        /// <summary>
        /// 列数
        /// </summary>
        public Int32 Column;
        /// <summary>
        /// X轴正向运动点
        /// </summary>
        public float[] xFwd = new float[80];
        /// <summary>
        /// X轴负向运动点
        /// </summary>
        public float[] xRev = new float[80];
        /// <summary>
        /// Y轴运动点
        /// </summary>
        public float[] yPos = new float[80];
    }


    public class MapConfi
    {
        /// <summary>
        /// 所属轨道模组
        /// </summary>
        public ConveyorModuleE Module;
        /// <summary>
        /// 线体方向
        /// </summary>
        public int LineDirection;
        /// <summary>
        /// 轨道定轨轴
        /// </summary>
        public int WAxisFixed;
        /// <summary>
        /// 负限位点
        /// </summary>
        public Position limitP;
        /// <summary>
        /// 正限位点
        /// </summary>
        public Position limitN;
        /// <summary>
        /// 方向X
        /// </summary>
        public int DirectionX;
        /// <summary>
        /// 方向Y
        /// </summary>
        public int DirectionY;
        /// <summary>
        /// 步距X
        /// </summary>
        public float StepX;
        /// <summary>
        /// 步距Y
        /// </summary>
        public float StepY;
        /// <summary>
        /// 进板起点X
        /// </summary>
        public float StartX;
        /// <summary>
        /// 进板起点Y
        /// </summary>
        public float StartY;
    }


    public class MapPath
    {
        /// <summary>
        /// 所属轨道模组
        /// </summary>
        public ConveyorModuleE Module { get => config.Module; }
        /// <summary>
        /// 比率
        /// </summary>
        private const Int32 ratio = 100;
        /// <summary>
        /// 路径配置
        /// </summary>
        private MapConfi config;
        /// <summary>
        /// 行数
        /// </summary>
        private int row;
        /// <summary>
        /// 列数
        /// </summary>
        public int column;
        /// <summary>
        /// 默认构造函数
        /// </summary>
        /// <param name="calibrate"></param>
        public MapPath(MapConfi mapConfig) 
        {   
            config = mapConfig;
        }
        /// <summary>
        /// 点拍计算路径行数和列数
        /// </summary>
        /// <param name="length"></param>
        /// <param name="width"></param>
        /// <param name="xmode"></param>
        /// <param name="ymode"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        private int MapCalc(
            float length, 
            float width, 
            int xmode, 
            int ymode, 
            int offset,
            float startx,float starty)
        {
            Int32 xdist;
            Int32 ydist;

            Int32 xlength = (Int32)(length * ratio);
            Int32 ywidth = (Int32)(width * ratio);

            Int32 xstep = (int)(config.StepX * ratio);
            Int32 ystep = (int)(config.StepY * ratio);
            Int32 xposi = (int)(startx * ratio);
            Int32 yposi = (int)(starty * ratio);
            Int32 xlmtp = (int)(config.limitP.x * ratio);
            Int32 xlmtn = (int)(config.limitN.x * ratio);
            Int32 ylmtp = (int)(config.limitP.y * ratio);
            Int32 ylmtn = (int)(config.limitN.y * ratio);

            if (xlength < 0 || ywidth < 0)
            {
                Logger.Logout($"PCB尺寸错误,长:{length},宽:{width}");
                return -1;
            }

            if (ywidth % ystep != 0)
            {
                row = ywidth / ystep + 1;
            }
            else
            {
                row = ywidth / ystep;
            }

            if (xlength % xstep != 0)
            {
                column = xlength / xstep + 1;
            }
            else
            {
                column = xlength / xstep;
            }

            if (xmode == 0)
            {
                xdist = xposi - (column - 1) * xstep - offset;
            }
            else
            {
                xdist = xposi + (column - 1) * xstep + offset;
            }

            if (ymode == 0)
            {
                ydist = yposi - (row - 1) * ystep;
            }
            else
            {
                ydist = yposi + (row - 1) * ystep;
            }

            if (xdist < xlmtn || ydist < ylmtn || xdist > xlmtp || ydist > ylmtp)
            {
                Logger.Logout($"PCB尺寸({length},{width})规划超过软件限位({xdist},{ydist}),xmode={xmode},ymode={ymode}.");
                return -1;
            }

            return 0;
        }
        /// <summary>
        /// 点拍路径点规划
        /// </summary>
        /// <param name="length"></param>
        /// <param name="width"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public MapPoint MapPointPlan(float length, float width, float startx, float starty)
        {
            if (startx.IsZero())
            {
                startx = config.StartX;
            }
            if (starty.IsZero())
            {
                starty = config.StartY;
            }
            MapPoint mapPoint = new MapPoint();
            Int32 xstep = (int)(config.StepX * ratio);
            Int32 ystep = (int)(config.StepY * ratio);
            Int32 xposi = (int)(startx * ratio);
            Int32 yposi = (int)(starty * ratio);
            Int32 xmode;
            Int32 ymode;

            if ((config.LineDirection == 0 && config.DirectionX == 0)
                || (config.LineDirection == 1 && config.DirectionX == 1))
            {
                xmode = 0;
            }
            else
            {
                xmode = 1;
            }
            if ((config.WAxisFixed == 0 && config.DirectionY == 0)
                || (config.WAxisFixed == 1 && config.DirectionY == 1))
            {
                ymode = 0;
            }
            else
            {
                ymode = 1;
            }

            if (MapCalc(length, width, xmode, ymode, 0, startx, starty) != 0)
            {
                return mapPoint;
            }

            for (int i = 0; i < row; i++)
            {
                if (i % 2 == 0)
                {
                    for (int j = 0; j < column; j++)
                    {
                        mapPoint.Positions.Add(new Position((float)xposi / ratio, (float)yposi/ ratio));
                        if (j != column - 1)
                        {
                            if (xmode == 0)
                            {
                                xposi -= xstep;
                            }
                            else
                            {
                                xposi += xstep;
                            }
                        }
                    }
                }
                else
                {
                    for (int j = 0; j < column; j++)
                    {
                        mapPoint.Positions.Add(new Position((float)xposi / ratio, (float)yposi / ratio));
                        if (j != column - 1)
                        {
                            if (xmode == 0)
                            {
                                xposi += xstep;
                            }
                            else
                            {
                                xposi -= xstep;
                            }
                        }
                    }
                }

                if (ymode == 0)
                {
                    yposi -= ystep;
                }
                else
                {
                    yposi += ystep;
                }
            }

            mapPoint.Row = row;
            mapPoint.Column = column;
            return mapPoint;
        }
        /// <summary>
        /// 获取
        /// </summary>
        /// <param name="posx"></param>
        /// <param name="posy"></param>
        /// <param name="lenx"></param>
        /// <param name="leny"></param>
        /// <returns></returns>
        public List<int> MapPointGrabPositionIndex(float posx, float posy, float lenx, float leny)
        {
            List<int> indexs = new List<int>();
            Int32[] rows = new int[2];
            Int32[] cols = new int[2];
            Int32 xstep = (int)(config.StepX * ratio);
            Int32 ystep = (int)(config.StepY * ratio);
            Int32 xlength = (int)(lenx * ratio);
            Int32 ylength = (int)(leny * ratio);
            Int32 xposi = (int)(posx * ratio);
            Int32 yposi = (int)(posy * ratio);

            rows[0] = Math.Abs((yposi - ylength / 2) / ystep);
            cols[0] = Math.Abs((xposi - xlength / 2) / xstep);
            rows[1] = Math.Abs((yposi + ylength / 2) / ystep);
            cols[1] = Math.Abs((xposi + xlength / 2) / xstep);

            if (cols[0] > column || cols[1] > column || rows[0] > row || rows[1] > row)
            {
                Logger.Logout($"行列越界,目标区域:中心点({posx},{posy}),长({lenx}),宽({leny}),获知目标区域行列:起始({rows[0]},{cols[0]}),结束({rows[1]},{cols[1]})>拍照({row},{column})");
                return indexs;
            }
            for (int i = 0; i < 2; i++)
            {
                for (int j = 0; j < 2; j++)
                {
                    int index = 0;
                    if (rows[i] % 2 == 0)
                    {
                        index = rows[i] * column + cols[j];
                    }
                    else
                    {
                        index = rows[i] * column + (column - cols[j] - 1);
                    }

                    if (!indexs.Contains(index))
                    {
                        indexs.Add(index);
                    }
                }
            }

            return indexs;
        }

        /// <summary>
        /// 飞拍路径规划
        /// </summary>
        /// <param name="length"></param>
        /// <param name="width"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public MapFlying MapFlyingPlan(float length, float width)
        {
            MapFlying mapFlying = new MapFlying();
            Int32 xstep = (int)(config.StepX * ratio);
            Int32 ystep = (int)(config.StepY * ratio);
            Int32 xposi = (int)(config.StartX * ratio);
            Int32 yposi = (int)(config.StartY * ratio);
            Int32 xmode;
            Int32 ymode;

            if ((config.LineDirection == 0 && config.DirectionX == 0)
                || (config.LineDirection == 1 && config.DirectionX == 1))
            {
                xmode = 0;
            }
            else
            {
                xmode = 1;
            }

            ymode = config.DirectionY;

            if (MapCalc(length, width, xmode, ymode, 600, -100000, -100000) != 0)
            {
                return mapFlying;
            }

            for (int i = 0; i < column; i++)
            {
                if (xmode == 0)
                {
                    mapFlying.xRev[i] = (float)xposi / ratio;
                    mapFlying.xFwd[column - i - 1] = mapFlying.xRev[i];
                    xposi -= xstep;
                }
                else
                {
                    mapFlying.xFwd[i] = (float)xposi / ratio;
                    mapFlying.xRev[column - i - 1] = mapFlying.xFwd[i];
                    xposi += xstep;
                }

                //Logger.Logout($"XRev{i}:{map.xRev[i]}");
                //Logger.Logout($"XFwd{points.Column - i - 1}:{map.xFwd[points.Column - i - 1]}");
            }

            for (int i = 0; i < row; i++)
            {
                if (ymode == 0)
                {
                    mapFlying.yPos[i] = (float)yposi / ratio;
                    yposi -= ystep;
                }
                else
                {
                    mapFlying.yPos[i] = (float)yposi / ratio;
                    yposi += ystep;
                }
                //Logger.Logout($"YRev{i}:{map.yRev[i]}");
            }
            mapFlying.Row = row;
            mapFlying.Column = column;
            return mapFlying;
        }
    }
}
